package com.yitiao.spring.ioc;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.yitiao.spring.core.BeanContainer;
import com.yitiao.spring.ioc.annotation.Autowired;
import com.yitiao.spring.utils.ClassUtil;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.Set;

@Slf4j
public class DependencyInjector {

    private BeanContainer beanContainer;
    public DependencyInjector(){
        beanContainer = BeanContainer.getInstance();
    }

    public void doIoc(){
        Set<Class<?>> classSet = beanContainer.getClasses();
        if(CollectionUtil.isEmpty(classSet)){
            log.warn("empty classSet in BeanContainer");
            return;
        }
        for (Class<?> clazz: classSet) {
            Field[] fields = clazz.getDeclaredFields();
            if(fields.length>0){
                for (Field field: fields) {
                    if (field.isAnnotationPresent(Autowired.class)){
                        Autowired autowired = field.getAnnotation(Autowired.class);
                        String autowiredValue = autowired.value();
                        //4.获取这些成员变量的类型
                        Class<?> fieldClass = field.getType();
                        //5.获取这些成员变量的类型在容器里对应的实例
                        Object fieldValue = getFieldInstance(fieldClass, autowiredValue);
                        if(fieldValue == null){
                            throw new RuntimeException("unable to inject relevant type，target fieldClass is:" + fieldClass.getName() + " autowiredValue is : " + autowiredValue);
                        } else {
                            //6.通过反射将对应的成员变量实例注入到成员变量所在类的实例里
                            Object targetBean =  beanContainer.getBean(clazz);
                            ClassUtil.setField(field, targetBean, fieldValue, true);
                        }
                    }
                }
            }
        }

    }

    private Object getFieldInstance(Class<?> fieldClass, String autowiredValue) {
        // 如果注解的值为空，获取成员变量的类型即可
        // 如果注解value不为空，根据value获取对应类（类名查找实例）
        Object fieldValue = beanContainer.getBean(fieldClass);
        if (fieldValue != null){
            return fieldValue;
        } else {
            Class<?> implementedClass = getImplementedClass(fieldClass, autowiredValue);
            if(implementedClass != null){
                return beanContainer.getBean(implementedClass);
            } else {
                return null;
            }
        }
    }

    /**
     * 获取接口的实现类
     */
    private Class<?> getImplementedClass(Class<?> fieldClass, String autowiredValue) {
        Set<Class<?>> classSet =  beanContainer.getClassesBySuper(fieldClass);
        if(CollectionUtil.isNotEmpty(classSet)){
            if(StrUtil.isBlank(autowiredValue)){
                if(classSet.size() == 1){
                    return classSet.iterator().next();
                } else {
                    //如果多于两个实现类且用户未指定其中一个实现类，则抛出异常
                    throw new RuntimeException("multiple implemented classes for " + fieldClass.getName() + " please set @Autowired's value to pick one");
                }
            } else {
                for(Class<?> clazz : classSet){
                    if(autowiredValue.equals(clazz.getSimpleName())){
                        return clazz;
                    }
                }
            }
        }
        return null;
    }

}
